<!--
 * @Descripttion:  
 * @version:  
 * @Author: chenxf
 * @Date: 2023-01-05 16:21:53
-->
<template lang="">
  <div class="container-upload">
    <input
      :multiple="multiple"
      ref="btnUpload"
      :accept="accept"
      type="file"
      @change="e => handleUpload(e.target.files)"
      style="display: none"
    />
    <div class="containerUploadedList">
      <template v-if="listType == 'picture-card'">
        <!-- 上传列表 -->
        <div
          class="uploadedItem "
          v-for="(item, index) in fileList"
          :key="index"
          :style="{
            width: cardSize,
            height: cardSize
          }"
          :class="{ hideName: !showName }"
        >
          <div v-if="isImg(getNameSuffix(getFileName(item)))" class="uploadedItemImgWrapper" :class="">
            <img class="uploadedItemImg" :src="getUrlJoinToken(item.url, item)" alt="" />
          </div>
          <svg v-else viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2943">
            <path
              d="M128 341.333333l256.128-256h469.12C876.8 85.333333 896 104.746667 896 127.658667v768.682666a42.368 42.368 0 0 1-42.368 42.325334H170.368A42.666667 42.666667 0 0 1 128 895.701333V341.333333z m298.666667-192L192 384H426.666667V149.333333z"
              :fill="color"
            ></path>
          </svg>
          <div class="toolbar">
            <Preview
              title="预览"
              @click="previewImage(getUrlJoinToken(item.url, item))"
              v-if="isImg(getNameSuffix(getFileName(item))) && !hidePreview"
            ></Preview>
            <Download
              title="下载"
              v-if="!hideDownLoad"
              @click="downloadFile(getUrlJoinToken(item.url, item), getFileName(item))"
            ></Download>
            <DeleteIcon title="删除" v-if="disabled ? false : !hideDelete" @click="deleteItem(index, item.url, item)" />

            <!-- <Delete></Delete> -->
          </div>
          <div class="fileName" :title="getFileName(item)" v-show="showName">
            {{ getFileName(item) }}
          </div>
        </div>
        <!-- 上传按钮样式、上传状态样式 -->
        <div
          class="uploadedItem btn"
          :class="[{ disabled: disabled }]"
          :style="{
            width: cardSize,
            height: cardSize
          }"
          v-if="!hideUpload"
        >
          <svg v-if="isLoading" class="uploadedItem_loading" viewBox="0 0 1024 1024">
            <path
              :fill="color"
              d="M876.864 782.592c3.264 0 6.272-3.2 6.272-6.656 0-3.456-3.008-6.592-6.272-6.592-3.264 0-6.272 3.2-6.272 6.592 0 3.456 3.008 6.656 6.272 6.656z m-140.544 153.344c2.304 2.432 5.568 3.84 8.768 3.84a12.16 12.16 0 0 0 8.832-3.84 13.76 13.76 0 0 0 0-18.56 12.224 12.224 0 0 0-8.832-3.84 12.16 12.16 0 0 0-8.768 3.84 13.696 13.696 0 0 0 0 18.56zM552.32 1018.24c3.456 3.648 8.32 5.76 13.184 5.76a18.368 18.368 0 0 0 13.184-5.76 20.608 20.608 0 0 0 0-27.968 18.368 18.368 0 0 0-13.184-5.824 18.368 18.368 0 0 0-13.184 5.76 20.608 20.608 0 0 0 0 28.032z m-198.336-5.76c4.608 4.8 11.072 7.68 17.6 7.68a24.448 24.448 0 0 0 17.536-7.68 27.456 27.456 0 0 0 0-37.248 24.448 24.448 0 0 0-17.536-7.68 24.448 24.448 0 0 0-17.6 7.68 27.52 27.52 0 0 0 0 37.184z m-175.68-91.84c5.76 6.08 13.824 9.6 21.952 9.6a30.592 30.592 0 0 0 22.016-9.6 34.368 34.368 0 0 0 0-46.592 30.592 30.592 0 0 0-22.016-9.6 30.592 30.592 0 0 0-21.952 9.6 34.368 34.368 0 0 0 0 46.592z m-121.152-159.36c6.912 7.36 16.64 11.648 26.368 11.648a36.736 36.736 0 0 0 26.432-11.584 41.28 41.28 0 0 0 0-55.936 36.736 36.736 0 0 0-26.432-11.584 36.8 36.8 0 0 0-26.368 11.52 41.28 41.28 0 0 0 0 56zM12.736 564.672a42.88 42.88 0 0 0 30.784 13.44 42.88 42.88 0 0 0 30.784-13.44 48.128 48.128 0 0 0 0-65.216 42.88 42.88 0 0 0-30.72-13.44 42.88 42.88 0 0 0-30.848 13.44 48.128 48.128 0 0 0 0 65.216z m39.808-195.392a48.96 48.96 0 0 0 35.2 15.36 48.96 48.96 0 0 0 35.2-15.36 54.976 54.976 0 0 0 0-74.56 48.96 48.96 0 0 0-35.2-15.424 48.96 48.96 0 0 0-35.2 15.424 54.976 54.976 0 0 0 0 74.56zM168.32 212.48c10.368 11.008 24.96 17.408 39.68 17.408 14.592 0 29.184-6.4 39.552-17.408a61.888 61.888 0 0 0 0-83.84 55.104 55.104 0 0 0-39.616-17.408c-14.656 0-29.248 6.4-39.616 17.408a61.888 61.888 0 0 0 0 83.84zM337.344 124.8c11.52 12.16 27.712 19.264 43.968 19.264 16.256 0 32.448-7.04 43.968-19.264a68.672 68.672 0 0 0 0-93.184 61.248 61.248 0 0 0-43.968-19.264 61.248 61.248 0 0 0-43.968 19.264 68.736 68.736 0 0 0 0 93.184z m189.632-1.088c12.672 13.44 30.528 21.248 48.448 21.248s35.712-7.808 48.384-21.248a75.584 75.584 0 0 0 0-102.464A67.392 67.392 0 0 0 575.36 0c-17.92 0-35.776 7.808-48.448 21.248a75.584 75.584 0 0 0 0 102.464z m173.824 86.592c13.824 14.592 33.28 23.104 52.736 23.104 19.584 0 39.04-8.512 52.8-23.104a82.432 82.432 0 0 0 0-111.744 73.472 73.472 0 0 0-52.8-23.168c-19.52 0-38.912 8.512-52.736 23.168a82.432 82.432 0 0 0 0 111.744z m124.032 158.528c14.976 15.872 36.032 25.088 57.216 25.088 21.12 0 42.24-9.216 57.152-25.088a89.344 89.344 0 0 0 0-121.088 79.616 79.616 0 0 0-57.152-25.088c-21.184 0-42.24 9.216-57.216 25.088a89.344 89.344 0 0 0 0 121.088z m50.432 204.032c16.128 17.088 38.784 27.008 61.632 27.008 22.784 0 45.44-9.92 61.568-27.008a96.256 96.256 0 0 0 0-130.432 85.76 85.76 0 0 0-61.568-27.072c-22.848 0-45.44 9.984-61.632 27.072a96.192 96.192 0 0 0 0 130.432z"
            ></path>
          </svg>
          <div class="uploadInner" v-else @click="triggerUpload">
            <AddIcon :fill="color" />
            <div class="uploadInnerName">{{ isLoading ? '上传中' : this.text }}</div>
          </div>
        </div>
      </template>
      <template v-if="listType == 'text'">
        <!-- 上传按钮样式、上传状态样式 -->
        <div class="uploadedItem btn" v-if="!hideUpload">
          <svg v-if="isLoading" class="uploadedItem_loading" viewBox="0 0 1024 1024" version="1.1">
            <path
              :fill="color"
              d="M876.864 782.592c3.264 0 6.272-3.2 6.272-6.656 0-3.456-3.008-6.592-6.272-6.592-3.264 0-6.272 3.2-6.272 6.592 0 3.456 3.008 6.656 6.272 6.656z m-140.544 153.344c2.304 2.432 5.568 3.84 8.768 3.84a12.16 12.16 0 0 0 8.832-3.84 13.76 13.76 0 0 0 0-18.56 12.224 12.224 0 0 0-8.832-3.84 12.16 12.16 0 0 0-8.768 3.84 13.696 13.696 0 0 0 0 18.56zM552.32 1018.24c3.456 3.648 8.32 5.76 13.184 5.76a18.368 18.368 0 0 0 13.184-5.76 20.608 20.608 0 0 0 0-27.968 18.368 18.368 0 0 0-13.184-5.824 18.368 18.368 0 0 0-13.184 5.76 20.608 20.608 0 0 0 0 28.032z m-198.336-5.76c4.608 4.8 11.072 7.68 17.6 7.68a24.448 24.448 0 0 0 17.536-7.68 27.456 27.456 0 0 0 0-37.248 24.448 24.448 0 0 0-17.536-7.68 24.448 24.448 0 0 0-17.6 7.68 27.52 27.52 0 0 0 0 37.184z m-175.68-91.84c5.76 6.08 13.824 9.6 21.952 9.6a30.592 30.592 0 0 0 22.016-9.6 34.368 34.368 0 0 0 0-46.592 30.592 30.592 0 0 0-22.016-9.6 30.592 30.592 0 0 0-21.952 9.6 34.368 34.368 0 0 0 0 46.592z m-121.152-159.36c6.912 7.36 16.64 11.648 26.368 11.648a36.736 36.736 0 0 0 26.432-11.584 41.28 41.28 0 0 0 0-55.936 36.736 36.736 0 0 0-26.432-11.584 36.8 36.8 0 0 0-26.368 11.52 41.28 41.28 0 0 0 0 56zM12.736 564.672a42.88 42.88 0 0 0 30.784 13.44 42.88 42.88 0 0 0 30.784-13.44 48.128 48.128 0 0 0 0-65.216 42.88 42.88 0 0 0-30.72-13.44 42.88 42.88 0 0 0-30.848 13.44 48.128 48.128 0 0 0 0 65.216z m39.808-195.392a48.96 48.96 0 0 0 35.2 15.36 48.96 48.96 0 0 0 35.2-15.36 54.976 54.976 0 0 0 0-74.56 48.96 48.96 0 0 0-35.2-15.424 48.96 48.96 0 0 0-35.2 15.424 54.976 54.976 0 0 0 0 74.56zM168.32 212.48c10.368 11.008 24.96 17.408 39.68 17.408 14.592 0 29.184-6.4 39.552-17.408a61.888 61.888 0 0 0 0-83.84 55.104 55.104 0 0 0-39.616-17.408c-14.656 0-29.248 6.4-39.616 17.408a61.888 61.888 0 0 0 0 83.84zM337.344 124.8c11.52 12.16 27.712 19.264 43.968 19.264 16.256 0 32.448-7.04 43.968-19.264a68.672 68.672 0 0 0 0-93.184 61.248 61.248 0 0 0-43.968-19.264 61.248 61.248 0 0 0-43.968 19.264 68.736 68.736 0 0 0 0 93.184z m189.632-1.088c12.672 13.44 30.528 21.248 48.448 21.248s35.712-7.808 48.384-21.248a75.584 75.584 0 0 0 0-102.464A67.392 67.392 0 0 0 575.36 0c-17.92 0-35.776 7.808-48.448 21.248a75.584 75.584 0 0 0 0 102.464z m173.824 86.592c13.824 14.592 33.28 23.104 52.736 23.104 19.584 0 39.04-8.512 52.8-23.104a82.432 82.432 0 0 0 0-111.744 73.472 73.472 0 0 0-52.8-23.168c-19.52 0-38.912 8.512-52.736 23.168a82.432 82.432 0 0 0 0 111.744z m124.032 158.528c14.976 15.872 36.032 25.088 57.216 25.088 21.12 0 42.24-9.216 57.152-25.088a89.344 89.344 0 0 0 0-121.088 79.616 79.616 0 0 0-57.152-25.088c-21.184 0-42.24 9.216-57.216 25.088a89.344 89.344 0 0 0 0 121.088z m50.432 204.032c16.128 17.088 38.784 27.008 61.632 27.008 22.784 0 45.44-9.92 61.568-27.008a96.256 96.256 0 0 0 0-130.432 85.76 85.76 0 0 0-61.568-27.072c-22.848 0-45.44 9.984-61.632 27.072a96.192 96.192 0 0 0 0 130.432z"
            ></path>
          </svg>
          <div class="uploadInner" v-else @click="triggerUpload">
            <AddIcon :fill="color" />
            <div class="uploadInnerName">{{ isLoading ? '上传中' : this.text }}</div>
          </div>
          <!-- <AddIcon v-else @click="triggerUpload" />
          <!-- <svg v-else viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" @click="triggerUpload">
            <path
              :fill="color"
              d="M1024 640.192C1024 782.912 919.872 896 787.648 896h-512C123.904 896 0 761.6 0 597.504 0 451.968 94.656 331.52 226.432 302.976 284.16 195.456 391.808 128 512 128c152.32 0 282.112 108.416 323.392 261.12C941.888 413.44 1024 519.04 1024 640.192z m-341.312-139.84L512 314.24 341.312 500.48h341.376z m-213.376 0v256h85.376v-256H469.312z"
              p-id="2695"
            ></path>
          </svg> -->
          <!-- <div class="fileName">{{ isLoading ? '上传中' : '上传' }}</div> -->
        </div>
        <!-- 上传列表 -->
        <div class="uploadedList" v-for="(item, index) in fileList" :key="index">
          <ListIcon class="listIcon" />
          <div class="fileName" :title="getFileName(item)">
            <div @click="downloadFile(getUrlJoinToken(item.url, item), getFileName(item))">{{ getFileName(item) }}</div>
          </div>
          <Delete
            title="删除"
            v-if="disabled ? false : !hideDelete"
            class="deleteIcon"
            @click="deleteItem(index, item.url, item)"
          ></Delete>
        </div>
      </template>
    </div>
  </div>
</template>
<script>
import debounce from 'lodash/debounce'
import axios from '../api/index'
import Preview from '../Icon/Preview.vue'
import Download from '../Icon/Download.vue'
import Delete from '../Icon/Delete.vue'
import DeleteIcon from '../Icon/DeleteIcon.vue'
import ListIcon from '../Icon/ListIcon.vue'
import AddIcon from '../Icon/AddIcon'
import saveAs from '../lib/FileSaver.js'
// import FileSaver from 'file-saver'
export default {
  name: 'HcUpload',
  props: {
    // token
    token: {
      type: String,
      required: false
    },
    //模块路径
    filePath: { type: String },
    // 归属模块
    // belongModule: {
    //   type: String,
    //   required: true
    // },
    // 分块尺寸：1M
    partSize: {
      type: Number,
      default: 1024 * 1024
    },
    // 限制文件类型
    accept: {
      type: String,
      default: '*'
    },
    // 是否多文件上传(如果是antd组件方式可不传这参数)
    multiple: {
      type: Boolean,
      default: false
    },
    // 是否展示loading
    showLoading: {
      type: Boolean,
      default: false
    },
    color: {
      type: String,
      default: '#707070'
    },
    fileList: {
      type: Array,
      default: [],
      required: true
    },
    //上传文件接口url 数组为以下格式（走JOSS则带Josstoken）
    // {
    // 		"contextType": "",
    // 		"etag": "",
    // 		"id": 0,
    // 		"jossToken": "",
    // 		"filePath": "",
    // 		"objectNameSuffix": "",
    // 		"objectSize": 0,
    // 		"path": "",
    // 		"url": ""
    // 	}
    uploadUrl: {
      type: [Array]
      // required: true
    },
    //上传之前的函数
    beforeUpload: {
      type: [Function]
    },
    //token放到 header里的字段
    authorization: {
      type: String,
      default: 'X-Access-Token'
    },
    //上传模式类型
    // 1:从业务系统提供url
    // 2:JOSS中间件
    // 3:JOSS签证
    uploadType: {
      type: [String, Number],
      default: 1
    },
    //jossToken
    jossToken: {
      type: String
    },
    //signParam Joss提供的公钥密钥签名参数
    signParam: { type: String, required: false },
    //业务地址前缀
    uploadApiPath: {
      type: String
    },
    //文件数量上限
    maxFileNum: {
      type: [String, Number],
      default: 100
    },
    //上传列表的内建样式
    // text :附件列表形式
    // picture-card :卡片形式 -默认
    listType: {
      type: [String],
      validator: function(value) {
        return ['text', 'picture-card'].includes(value)
      },
      default: 'picture-card'
      // default: 'text'
    },
    //是否禁用操作，默认否
    disabled: {
      type: Boolean,
      default: false
    },
    // 隐藏下载、删除、查看、上传等操作
    // 下载 ：download
    // 删除 ：delete
    // 查看 ：preview
    // 上传 ：upload
    ignores: {
      type: Array,
      default: function() {
        return []
      }
    },
    //是否在卡片模式显示名字
    showName: {
      type: Boolean,
      default: false
    },
    //卡片模式的尺寸大小(外围大小)
    //默认 105px
    cardSize: {
      type: String,
      default: '105px'
    },
    //是否手机
    isMobile: {
      type: Boolean,
      default: false
    },
    text: {
      type: String,
      default: '上传'
    },
    //是否公共可读
    public: {
      type: Boolean,
      default: false
    }
  },
  components: {
    Preview,
    Download,
    Delete,
    ListIcon,
    AddIcon,
    DeleteIcon
  },
  data() {
    return {
      isLoading: false, //是否上传中(loading)
      uploadUrlSelf: '', // 上传地址
      objectName: '', // 对象名
      uploadId: undefined,
      chunkNum: 0, // 分块数量
      etags: [],
      files: [], // 上传的文件列表
      newInfos: [], // 新上传返回信息列表
      uploadIndex: 0, // 上传的文件下标
      postData: {}, //给父亲的参数
      jossTokenSelf: undefined // 内置用的jossToken,
    }
  },
  computed: {
    api() {
      return {
        objectPath: `/${this.uploadApiPath}/object-paths`,
        objectPrefix: `/${this.uploadApiPath}/object-prefix`,
        deleteObject: `/${this.uploadApiPath}/delete-object`
      }
    },
    //隐藏下载
    hideDownLoad() {
      let show = true
      if (this.ignores && this.ignores.length) {
        show = !this.ignores.includes('download')
      }
      return !show
    },
    //隐藏删除
    hideDelete() {
      let show = true
      if (this.ignores && this.ignores.length) {
        show = !this.ignores.includes('delete')
      }
      return !show
    },
    //隐藏预览
    hidePreview() {
      let show = true
      if (this.ignores && this.ignores.length) {
        show = !this.ignores.includes('preview')
      }
      return !show
    },
    //隐藏上传
    hideUpload() {
      let show = true
      if (this.ignores && this.ignores.length) {
        show = !this.ignores.includes('upload')
      }
      return !show
    }
  },
  watch: {
    fileList() {
      if (this.maxFileNum < this.fileList.length) {
        this.$emit('update:fileList', this.fileList.slice(0, this.maxFileNum))
      }
    }
  },
  created() {
    if (this.uploadApiPath && this.uploadType == 2) {
      this.getJossToken()
    }
    if (this.maxFileNum < this.fileList.length) {
      this.$emit('update:fileList', this.fileList.slice(0, this.maxFileNum))
    }
  },
  methods: {
    // 当前文件是否为图片
    isImg(type) {
      return /^.?(bmp|jpg|png|tif|gif|cx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw|WMF|webp|avif|apng|jpeg)$/.test(
        type
      )
    },
    //文件名
    getFileName(file) {
      if (!file) return
      let fileName = ''
      if (file.fileName) {
        fileName = file.fileName
      } else {
        let path = file.url.split('/')
        fileName = path[path.length - 1]
      }
      return fileName
    },
    //url自动加token
    getUrlJoinToken(url, file) {
      let urlSearch = url.split('?')
      if (this.uploadType == 1) {
        if (urlSearch.length == 2) {
          const obj = {}
          const paramArr = new URLSearchParams(urlSearch[1])
          paramArr.forEach((val, key) => {
            obj[key] = val
          })
          obj.token = this.token
          return (
            urlSearch[0] +
            '?' +
            Object.keys(obj)
              .map(i => {
                return i + '=' + obj[i]
              })
              .join('&')
          )
        } else {
          return url + '?token=' + this.token
        }
      } else {
        //JOSS时
        if (urlSearch.length == 2) {
          const obj = {}
          const paramArr = new URLSearchParams(urlSearch[1])
          paramArr.forEach((val, key) => {
            obj[key] = val
          })
          obj.jossToken = this.jossToken ? this.jossToken : file.jossToken
          if (this.jossTokenSelf) {
            obj.jossToken = this.jossTokenSelf
          }
          return (
            urlSearch[0] +
            '?' +
            Object.keys(obj)
              .map(i => {
                return i + '=' + obj[i]
              })
              .join('&')
          )
        } else {
          let jossToken = this.jossToken ? this.jossToken : file.jossToken
          if (this.jossTokenSelf) {
            jossToken = this.jossTokenSelf
          }
          return url + '?jossToken=' + jossToken
        }
      }
    },
    //获取文件后缀名
    getNameSuffix(fileName) {
      if (!fileName) return ''
      let fileNameArr = fileName.split('.')
      return fileNameArr[fileNameArr.length - 1]
    },
    //获取josstoken
    getJossToken() {
      axios({
        method: 'POST',
        url: this.api.objectPrefix,
        data: {
          filePath: this.filePath,
          preSign: ''
        },
        headers: {
          [this.authorization]: this.token
        }
      }).then(res => {
        this.jossTokenSelf = res.result.jossToken
      })
    },
    //删除文件
    deleteItem(index, url, item) {
      this.$emit('delete', item, ({ success }) => {
        if (success) {
          this.$emit('update:fileList', [...this.fileList.slice(0, index), ...this.fileList.slice(index + 1)])
        }
      })
    },
    // 触发选择文件
    triggerUpload() {
      if (this.disabled) {
        return
      }
      this.$refs.btnUpload.click()
    },
    // 获取上传信息新
    getUploadInfo(file) {
      let fileNameArr = file.name.split('.')
      if (this.uploadType == 2 && this.uploadApiPath == undefined) {
        this.postData = {
          ...this.uploadUrl[this.uploadIndex],
          fileSuffix: '.' + file.name.split('.')[fileNameArr.length - 1],
          fileType: file.type,
          fileName: file.name.replace(' ', '')
        }
        this.objectName = file.name
        this.uploadUrlSelf = this.uploadUrl[this.uploadIndex].url
        this.etags = []
        this.initChunking(file)
        return
      }
      if (this.uploadType == 3) {
        this.postData = {
          fileSuffix: '.' + file.name.split('.')[fileNameArr.length - 1],
          fileType: file.type,
          fileName: file.name.replace(' ', '')
        }
        this.objectName = file.name
        this.uploadUrlSelf = this.uploadUrl[this.uploadIndex].url
        this.etags = []
        this.initChunking(file)
        return
      }
      let params = {
        infos: [
          {
            fileName: file.name.replace(' ', ''),
            objectSize: file.size,
            contextType: file.type,
            token: this.token,
            objectNameSuffix: '.' + file.name.split('.')[fileNameArr.length - 1]
          }
        ]
      }
      if (this.filePath) {
        params.filePath = this.filePath
      }
      if (this.uploadType == 1 && this.uploadApiPath == undefined) {
        let _thisInfo = this.uploadUrl[this.uploadIndex]
        //给父亲的参数
        this.postData = {
          ..._thisInfo,
          fileSuffix: _thisInfo.objectNameSuffix,
          fileType: _thisInfo.contextType,
          fileName: file.name.replace(' ', '')
        }
        this.objectName = file.name
        this.uploadUrlSelf = _thisInfo.url
        this.etags = []
        this.initChunking(file)
        return
      } else {
        //保留以后统一用业务系统上传使用
        axios({
          method: 'POST',
          url: this.api.objectPath,
          data: params,
          headers: {
            [this.authorization]: this.token
          }
        })
          .then(res => {
            if (!res.success) {
              this.$emit('uploadError', res.message || '获取上传信息失败')
              this.handleUploaded()
              return
            }
            //给父亲的参数
            this.postData = {
              ...res.result.infos[0],
              fileSuffix: res.result.infos[0].objectNameSuffix,
              fileType: res.result.infos[0].contextType
            }
            this.objectName = file.name
            this.uploadUrlSelf = res.result.infos[0].url
            this.etags = []
            this.initChunking(file)
          })
          .catch(() => {
            this.$emit('uploadError', '获取上传信息失败')
            this.handleUploaded()
          })
      }
    },
    /**
     * 初始化分块
     * @param {*} file 上传文件
     */
    initChunking(file) {
      let params = {
        acl: this.public ? 2 : 1,
        uploads: ''
      }
      if (this.uploadType == 1) {
        params.token = this.token
      } else if (this.uploadType == 2) {
        params.jossToken = this.jossToken ? this.jossToken : this.uploadUrl[this.uploadIndex].jossToken
      } else if (this.uploadType == 3) {
        params = { ...params, ...this.signParam }
      }
      axios({
        method: 'POST',
        url: this.uploadUrlSelf,
        params
      })
        .then(res => {
          if (!res.success) {
            this.$emit('uploadError', res.message || '上传文件失败')
            this.handleUploaded()
            return
          }
          this.uploadId = res.result.uploadId
          this.chunkNum = Math.ceil(file.size / this.partSize)
          this.uploadFirstPart(file)
        })
        .catch(() => {
          this.$emit('uploadError', '上传文件失败')
          this.handleUploaded()
        })
    },
    /**
     * 上传第一块文件内容
     */
    uploadFirstPart(file) {
      let chunk = file.slice(0, this.partSize)
      if (this.chunkNum === 1) {
        chunk = file
      }
      const formData = new FormData()
      formData.append('file', chunk)
      let params = {
        offset: 0,
        partNumber: 1,
        partSize: this.chunkNum === 1 ? file.size : this.partSize,
        uploadId: this.uploadId
      }
      if (this.uploadType == 1) {
        params.token = this.token
      } else if (this.uploadType == 2) {
        params.jossToken = this.jossToken ? this.jossToken : this.uploadUrl[this.uploadIndex].jossToken
      } else if (this.uploadType == 3) {
        params = { ...params, ...this.signParam }
      }
      axios({
        method: 'PUT',
        url: this.uploadUrlSelf,
        Headers: {
          'Content-Type': 'multipart/form-data'
        },
        params: params,
        data: formData
      })
        .then(res => {
          if (res.success) {
            this.etags.push(res.result.etag)
            if (1 === this.chunkNum) {
              this.mergeUploadFile(file)
            } else {
              this.uploadPartAll(file)
            }
          } else {
            this.$emit('uploadError', res.message || '上传文件失败')
            this.handleUploaded()
          }
        })
        .catch(() => {
          this.$emit('uploadError', '上传文件失败')
          this.handleUploaded()
        })
    },
    /**
     * 并发分块上传剩余所有分块(除第一块外)
     */
    uploadPartAll(file) {
      let list = []
      for (let i = 2; i <= this.chunkNum; i++) {
        list.push(this.uploadPart(i, file, this.partSize * (i - 1), this.partSize * i))
      }
      Promise.all(list)
        .then(ress => {
          if (ress instanceof Array && ress.length && ress.every(res => res.success)) {
            this.mergeUploadFile(file)
          } else {
            this.$emit('uploadError', '上传分块文件失败')
            this.handleUploaded()
          }
        })
        .catch(() => {
          this.$emit('uploadError', '上传分块文件失败')
          this.handleUploaded()
        })
    },
    /**
     * 分块上传
     * @param {*} n 块数
     * @param {*} file 文件
     * @param {*} start 分块开始
     * @param {*} end 分块结束
     */
    uploadPart(n, file, start, end) {
      let chunk = file.slice(start, end)
      if (n === this.chunkNum && end > file.size) {
        chunk = file.slice(start)
      }
      const formData = new FormData()
      formData.append('file', chunk)
      const partSize = end > file.size ? file.size - start : end - start
      let params = {
        offset: (n - 1) * this.partSize,
        partNumber: n,
        partSize,
        uploadId: this.uploadId
      }
      if (this.uploadType == 1) {
        params.token = this.token
      } else if (this.uploadType == 2) {
        params.jossToken = this.jossToken ? this.jossToken : this.uploadUrl[this.uploadIndex].jossToken
      } else if (this.uploadType == 3) {
        params = { ...params, ...this.signParam }
      }
      return axios({
        method: 'PUT',
        url: this.uploadUrlSelf,
        Headers: {
          'Content-Type': 'multipart/form-data'
        },
        params,
        data: formData
      }).then(res => {
        if (res.success) {
          this.etags[n - 1] = res.result.etag
          return Promise.resolve(res)
        } else {
          return Promise.reject(res)
        }
      })
    },
    /**
     * 合并上传文件
     */
    mergeUploadFile(file) {
      let params = {
        uploadId: this.uploadId
      }
      if (this.uploadType == 1) {
        params.token = this.token
      } else if (this.uploadType == 2) {
        params.jossToken = this.jossToken ? this.jossToken : this.uploadUrl[this.uploadIndex].jossToken
      } else if (this.uploadType == 3) {
        params = { ...params, ...this.signParam }
      }
      axios({
        method: 'POST',
        url: this.uploadUrlSelf,
        params,
        data: this.etags
      })
        .then(res => {
          if (!res.success) {
            this.$emit('uploadError', res.message || '上传分块文件失败')
            this.handleUploaded()
            return
          }
          const tempData = Object.assign(res.result, this.postData)
          const params = {
            realPath: tempData.url,
            url: tempData.url,
            providerUrl: tempData.providerUrl,
            fileSize: tempData.objectSize,
            fileSuffix: tempData.fileSuffix,
            fileType: tempData.fileType,
            fileName: file.name.replace(' ', ''),
            storageLocation: 1,
            uid: file.uid
          }
          // this.$emit('uploaded', params)
          // this.ress.push(tempData)
          this.newInfos.push(params)
          this.$emit('update:fileList', [...this.fileList, params])
          if (this.uploadIndex >= this.files.length - 1) {
            this.$emit('uploaded', [...this.fileList, params], this.newInfos)
            this.handleUploaded()
            return
          }
          this.getUploadInfo(this.files[++this.uploadIndex])
        })
        .catch(() => {
          this.$emit('uploadError', '上传分块文件失败')
          this.handleUploaded()
        })
    },
    // 上传文件结束清空数据
    handleUploaded() {
      this.files = []
      this.uploadIndex = 0
      this.postData = {}
      this.isLoading = false
    },
    // 检查文件类型是否符合格式
    checkFileType(file) {
      const { accept } = this
      if (accept === '*') {
        return true
      }
      if (!accept.includes('/')) {
        return true
      }
      let [accept1, accept2] = accept.split('/')
      let [type1, type2] = file.type.split('/')
      if (accept1 !== type1) {
        return false
      }
      if (accept2 === '*') {
        return true
      }
      return accept2 === type2
    },
    // 上传触发事件
    handleUpload: debounce(function(files) {
      if ([].some.call(files, file => !this.checkFileType(file))) {
        this.$emit('uploadError', '上传文件类型不符合格式')
        this.files = []
        return
      }
      let newFilesLen = files.length
      let maxFileNum = Number(this.maxFileNum)
      let curFilesLen = this.fileList.length
      if (isNaN(maxFileNum)) {
        this.$emit('uploadError', '文件数量上限字段有误')
        return
      }
      if (maxFileNum - newFilesLen - curFilesLen < 0) {
        this.$emit('uploadError', `文件数量超出,文件数量上限为:${maxFileNum},当前文件数量:${newFilesLen + curFilesLen}`)
        return
      }
      this.files = files
      this.newInfos = []
      const file = files[0]
      if (!file) {
        return
      }
      if (this.beforeUpload && typeof this.beforeUpload === 'function' && !this.uploadApiPath) {
        //尝试非promise对象后再重新执行
        try {
          this.beforeUpload(files).then(res => {
            this.uploadIndex = 0
            this.isLoading = true
            this.getUploadInfo(file)
          })
        } catch (e) {
          this.uploadIndex = 0
          this.isLoading = true
          this.getUploadInfo(file)
        }
      } else {
        this.uploadIndex = 0
        this.isLoading = true
        this.getUploadInfo(file)
      }
      // if (!this.beforeUpload) {
      //   return true;
      // }
    }, 100),
    // 上传触发事件-antd
    handleUploadAntd(file) {
      this.files.push(file)
      this.handleUpload(this.files)
    },
    previewImage(url) {
      this.$viewerApi({ images: [url] })
    },
    downloadFile(url, name) {
      if (this.hideDownLoad) return
      saveAs(url, name)
    }
  }
}
</script>
<style lang="less" scoped>
@keyframes loading {
  to {
    transform: rotate(360deg);
  }
}
.container-upload {
  position: relative;
  .containerUploadedList {
    position: relative;
    display: flex;
    flex-flow: row wrap;
    .uploadedItem {
      position: relative;
      width: 104px;
      height: 104px;
      border-radius: 5px;
      border: solid 1px rgb(219, 218, 218);
      margin-right: 8px;
      margin-bottom: 8px;
      &.btn {
        cursor: pointer;
        border: 1px dashed rgb(219, 218, 218);
        align-items: center;
        display: inline-flex;
        justify-content: center;
        &:hover {
          border: 1px dashed #1890ff;
        }
      }
      &.disabled {
        cursor: not-allowed;
        svg {
          cursor: not-allowed;
        }
      }
      .uploadedItemImgWrapper {
        width: 100%;
        height: 80%;
        display: inline-flex;
        align-items: center;
        justify-content: center;
      }
      .uploadedItemImg {
        // position: absolute;
        // top: 1%;
        // left: 10%;
        max-width: 80%;
        max-height: 80%;
        cursor: pointer;
      }
      > svg {
        position: absolute;
        top: 1%;
        left: 10%;
        width: 80%;
        height: 80%;
        cursor: pointer;
      }
      .fileName {
        position: absolute;
        left: 10%;
        width: 80%;
        text-align: center;
        bottom: 1%;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        height: 20px;
        line-height: 20px;
      }
      .uploadedItem_loading {
        top: 35%;
        left: 35%;
        width: 30%;
        height: 30%;
        animation: loading 1.5s linear infinite;
        cursor: auto;
      }
      .deleteIcon {
        width: 20%;
        height: 20%;
        top: 0;
        right: 0;
        left: auto;
        &:hover {
          background: rgba(0, 0, 0, 0.1);
        }
      }
      &:hover {
        > .toolbar {
          display: inline-flex;
        }
      }
      &.hideName {
        .uploadedItemImgWrapper {
          width: 100%;
          height: 100%;
          .uploadedItemImg {
            // position: absolute;
            // top: 1%;
            // left: 10%;
            max-width: 94%;
            max-height: 94%;
            cursor: pointer;
          }
        }
        > svg {
          position: absolute;
          top: 1%;
          left: 1%;
          width: 99%;
          height: 99%;
          cursor: pointer;
        }
      }
    }

    .uploadInner {
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background-color: #f7f7f7;
      .uploadInnerName {
        padding-top: 10px;
        font-size: 12px;
        line-height: 14px;
        // color: rgb(210, 210, 210);
      }
    }
    .uploadedList {
      position: relative;
      width: 100%;
      height: 30px;
      // border: solid 1px rgb(219, 218, 218);
      // margin-right: 8px;
      margin-bottom: 6px;
      display: flex;
      align-items: center;
      font-size: 14px;
      padding: 0 6px;
      &:hover {
        background-color: #e6f7ff;
        .deleteIcon {
          display: inline-flex;
          visibility: visible;
        }
      }
      .deleteIcon {
        width: 16px;
        height: 16px;
        fill: currentcolor;
        color: rgba(0, 0, 0, 0.45);
        cursor: pointer;
        visibility: hidden;
      }
      .listIcon {
        width: 16px;
        height: 16px;
        color: rgba(0, 0, 0, 0.45);
        fill: currentcolor;
      }
      .fileName {
        padding: 0 6px;
        flex: 1;
        line-height: 30px;
        font-size: 14px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        display: flex;
        cursor: pointer;
        > div {
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          color: #1890ff;
        }
      }
    }
    .toolbar {
      background: rgba(0, 0, 0, 0.5);
      width: 100%;
      height: 100%;
      left: 0;
      align-items: center;
      justify-content: center;
      position: absolute;
      display: none;
      font-size: 16px;
      color: #d2d2d2;
      > svg {
        width: 16px;
        color: rgb(210, 210, 210);
        fill: currentcolor;
        margin-left: 4px;
        cursor: pointer;
        &:first-child {
          margin-left: 0px;
        }
        &:hover {
          color: rgb(255, 255, 255);
        }
      }
      .svg-span {
        margin-left: 4px;
      }
    }
  }
}
</style>
